package com.gzyct.m.api.common.partner;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gzyct.m.api.common.util.JsonUtils;
import com.gzyct.m.api.common.util.SpringUtils;

public class PartnerService {

	private static final Logger logger = LoggerFactory.getLogger(PartnerService.class);

	private static CloseableHttpClient httpClient = null;

	private static final String PROP_GET_SIGN_KEY_URL = "yctapi.common.partner.getSignKey.url";
	private static final String PROP_PERMIT_URL = "yctapi.common.partner.permit.url";

	private static final String CACHE_PERFIX_PERMIT = "PERMIT";
	private static final String CACHE_PREFIX_SIGNKEY = "SIGNKEY";

	static {
		RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000).setSocketTimeout(5000)
				.build();
		httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).evictExpiredConnections()
				.build();
		// TODO: Retry strategy
	}

	public static String getSignKey(String channelCode, String signType) throws Exception {

		String cachedSignKey = PartnerCache.getInstantce().get(String.class, CACHE_PREFIX_SIGNKEY,
				channelCode, signType);
		if (cachedSignKey != null) {
			logger.debug("partner get sign key from cache for {} {}", channelCode, signType);
			return cachedSignKey;
		}
		logger.debug("partner get sign key from remote for {} {}", channelCode, signType);
		Map<String, String> params = new HashMap<String, String>();
		params.put("channelCode", channelCode);
		params.put("signType", signType);
		String respString = send(getProperty(PROP_GET_SIGN_KEY_URL), params);
		PartnerSignKeyResp resp = JsonUtils.toObject(respString, PartnerSignKeyResp.class);
		if (resp.checkSuccess()) {
			PartnerCache.getInstantce().put(resp.getSignKey(), CACHE_PREFIX_SIGNKEY, channelCode, signType);
		} else {
			throw new RuntimeException("get partner sign key error, return is " + resp);
		}
		return resp.getSignKey();
	}

	public static Boolean permit(String channelCode, String service) throws Exception {
		Boolean cachedPermit = PartnerCache.getInstantce().get(Boolean.class, CACHE_PERFIX_PERMIT,
				channelCode, service);
		if (cachedPermit != null) {
			logger.debug("partner get permit from cache for {} {}", channelCode, service);
			return cachedPermit;
		}
		logger.debug("partner get permit from remote for {} {}", channelCode, service);
		Map<String, String> params = new HashMap<String, String>();
		params.put("channelCode", channelCode);
		params.put("service", service);
		String respString = send(getProperty(PROP_PERMIT_URL), params);
		PartnerPermitResp resp = JsonUtils.toObject(respString, PartnerPermitResp.class);
		if (resp.checkSuccess()) {
			PartnerCache.getInstantce().put(resp.getIsPermit(), CACHE_PERFIX_PERMIT, channelCode, service);
		} else {
			throw new RuntimeException("get partner premit error, return is " + resp);
		}
		return resp.getIsPermit();
	}

	private static String getProperty(String key) {
		String value = SpringUtils.getProperty(key);
		if (value == null) {
			throw new RuntimeException("no value found for spring property key " + key);
		}
		logger.debug("partner get prop {} : {}", key, value);
		return value;
	}

	private static String send(String url, Map<String, String> params) throws Exception {

		CloseableHttpResponse httpResponse = null;
		try {
			HttpPost post = new HttpPost(url);
			List<NameValuePair> requestParams = new ArrayList<NameValuePair>();
			for (Iterator<Entry<String, String>> it = params.entrySet().iterator(); it.hasNext();) {
				Entry<String, String> next = it.next();
				requestParams.add(new BasicNameValuePair(next.getKey(), next.getValue()));
			}
			UrlEncodedFormEntity uefe = new UrlEncodedFormEntity(requestParams);
			post.setEntity(uefe);
			httpResponse = httpClient.execute(post);
			HttpEntity entity = httpResponse.getEntity();
			InputStream is = entity.getContent();
			return IOUtils.toString(is, "UTF-8");
		} finally {
			if (httpResponse != null) {
				try {
					httpResponse.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
